<template>
  <div>
    <canvas id="gltf-model"></canvas>
    <div id="label" class="info-card" style="display: none"></div>
  </div>
</template>

<script>
import * as THREE from 'three/build/three.module.js'
import {GLTFLoader} from 'three/examples/jsm/loaders/GLTFLoader.js'
import {OrbitControls} from 'three/examples/jsm/controls/OrbitControls'

export default {
  name: "GLTFModule",
  props: ['devId'],
  data() {
    return {
      // 控制信息卡片是否显示
      showInfoCard: false
    }
  },
  mounted() {
    this.initThree()
  },
  methods: {
    initThree() {
      let self = this
      const scene = new THREE.Scene()
      scene.background = new THREE.Color('#eee')
      // scene.fog = new THREE.Fog('#eee', 20, 100)

      const canvas = document.querySelector('#gltf-model')
      const renderer = new THREE.WebGLRenderer({canvas, antialias: true})
      renderer.shadowMap.enabled = true

      const camera = new THREE.PerspectiveCamera(
          75,
          window.innerWidth / window.innerHeight,
          0.1,
          1000
      )
      camera.position.z = 10

      // 鼠标点击触发的方法
      function onMouseClick(event) {

        // 获取 raycaster 和所有模型相交的数组，其中的元素按照距离排序，越近的越靠前
        let intersects = getIntersects(event);

        // 获取选中最近的 Mesh 对象
        if (intersects.length !== 0 && intersects[0].object instanceof Object) {
          let selectObject = intersects[0].object;
          renderDiv(selectObject)
          self.showInfoCard = !self.showInfoCard
        }
      }

      // 获取与射线相交的对象数组
      function getIntersects(event) {
        event.preventDefault();
        console.log("event.clientX:" + event.clientX)
        console.log("event.clientY:" + event.clientY)

        // 声明 raycaster 和 mouse 变量
        let raycaster = new THREE.Raycaster();
        let mouse = new THREE.Vector2();

        // 通过鼠标点击位置,计算出 raycaster 所需点的位置,以屏幕为中心点,范围 -1 到 1
        mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
        mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;

        //通过鼠标点击的位置(二维坐标)和当前相机的矩阵计算出射线位置
        raycaster.setFromCamera(mouse, camera);

        // 返回选中的对象: 获取与射线相交的对象数组，其中的元素按照距离排序，越近的越靠前
        return raycaster.intersectObjects(scene.children);
      }

      // 更新div的信息
      function renderDiv(object) {
        // 是否显示信息卡片
        if (self.showInfoCard) {
          document.getElementById("label").style.display = "block"
        } else {
          document.getElementById("label").style.display = "none"
        }
        // 修改 div 的位置
        document.onmousemove = function (e) {
          document.getElementById("label").style.left = (e.pageX - 80) + "px"
          document.getElementById("label").style.top = (e.pageY - 40) + "px"
          document.getElementById("label").style.backgroundColor = "rgba(0, 0, 0, 0.5)"
        }

        // 显示模型信息
        document.getElementById("label").innerHTML = "name:" + object.name + "<br/>" + "实时监测水质信息"
      }

      addEventListener('click', onMouseClick, false);

      // 导入泳池场馆的gltf模型
      const gltfLoader = new GLTFLoader()
      gltfLoader.load('/models/pool/untitled.gltf',
          (gltf) => {
            console.log(gltf.scene)
            let model = gltf.scene
            scene.add(model)
          },
          (xhr) => {
            console.log((xhr.loaded / xhr.total * 100) + '% loaded')
          },
          (error) => {
            console.log('An error happened: ' + error);
          }
      )

      // 导入设备gltf模型
      const deviceLoader = new GLTFLoader()
      deviceLoader.load('/models/device/device.gltf',
          (gltf) => {
            let model = gltf.scene
            model.position.x += 15
            model.rotateZ(Math.PI / 2)
            model.scale.set(0.3, 0.3, 0.3)
            model.name = "检测设备demo电子板"

            // 添加一个可以被鼠标点击到的mesh
            let geometry = new THREE.BoxGeometry(1, 1, 0.2)
            let material = new THREE.MeshNormalMaterial()
            // 是否透明
            material.transparent = true
            // 透明度
            material.opacity = 0
            let mesh = new THREE.Mesh(geometry, material)
            mesh.position.set(model.position.x, model.position.y, model.position.z)
            mesh.rotateY(Math.PI / 2)
            mesh.name = "检测设备demo电子板"

            scene.add(mesh)
            scene.add(model)
          },
          (xhr) => {
            console.log((xhr.loaded / xhr.total * 100) + '% loaded')
          },
          (error) => {
            console.log('An error happened: ' + error);
          }
      )

      const hemLight = new THREE.HemisphereLight(0xffffff, 0xffffff, 0.6)
      hemLight.position.set(0, 48, 0)
      scene.add(hemLight)

      const dirLight = new THREE.DirectionalLight(0xffffff, 0.6)
      //光源等位置
      dirLight.position.set(-10, 8, -5)
      //可以产生阴影
      dirLight.castShadow = true
      dirLight.shadow.mapSize = new THREE.Vector2(1024, 1024)
      scene.add(dirLight)

      const controls = new OrbitControls(camera, renderer.domElement)
      controls.enableDamping = true

      function animate() {
        controls.update()
        renderer.render(scene, camera)
        requestAnimationFrame(animate)

        if (resizeRendererToDisplaySize(renderer)) {
          const canvas = renderer.domElement
          camera.aspect = canvas.clientWidth / canvas.clientHeight
          camera.updateProjectionMatrix()
        }
      }

      animate()

      function resizeRendererToDisplaySize(renderer) {
        const canvas = renderer.domElement
        let width = window.innerWidth
        let height = window.innerHeight
        let canvasPixelWidth = canvas.width / window.devicePixelRatio
        let canvasPixelHeight = canvas.height / window.devicePixelRatio

        const needResize =
            canvasPixelWidth !== width || canvasPixelHeight !== height
        if (needResize) {
          renderer.setSize(width, height, false)
        }
        return needResize
      }
    },
  },
}
</script>

<style scoped>
#gltf-model {
  width: 100%;
  height: 100%;
  position: fixed;
  left: 0;
  top: 0;
}

#label {
  position: absolute;
  width: 150px;
  padding: 10px;
  background: rgba(255, 255, 255, 0);
  line-height: 1;
  border-radius: 5px;
}

.info-card {
  color: #f0f0f0;
  height: 200px ;
}
</style>
